各位應該都有在 Youtube 看過影片的經驗吧!如果想要看到影片,可以直接在 Youtube 上面搜尋關鍵字,或者在各別 Youtuber 的頻道中看到他們的影片,也可以按下訂閱按鈕,那麼未來當 Youtuber 有新影片上架時,就可以第一時間收到通知,這也是今天要討論的主題,如何透過 Observer模式去實現「訂閱並且主動通知」的功能。
定義物件間的一種一對多的相依關係,當一個物件的狀態發生改變時,所有相依於它的物件都將得到通知並自動更新。
(圖片來源: https://www.cs.mcgill.ca/~hv/classes/CS400/01.hchen/doc/observer/observer.gif)
Observer
是抽象類別,字面上是觀察者,會實作Update
改寫更新時要做的事。Subject
也是抽象類別,字面上是主題,也就是被觀察者,會去實現註冊訂閱者、移除訂閱者以及通知訂閱者的功能,其中會去聚合Observer
,當觸發通知訂閱者的功能時,就會對聚合Observer
做Update
的呼叫。using System;
using System.Collections.Generic;
namespace DAY18_Observer
{
public class Program
{
static void Main(string[] args)
{
// 建立 Youtuber
Youtuber youtuber = new Youtuber("老高");
// 訂閱者 Howard & John
Subscriber Howard = new Subscriber("Howard");
Subscriber John = new Subscriber("John");
// 訂閱者訂閱 Youtuber
youtuber.RegisterSubscriber(Howard);
youtuber.RegisterSubscriber(John);
Console.WriteLine("---------");
// Youtuber上傳新影片
youtuber.UploadNewVideo("9月份新影片");
Console.WriteLine("---------");
// John取消訂閱 Youtuber
youtuber.RemoveSubscriber(John);
youtuber.UploadNewVideo("10月份新影片");
}
}
public abstract class Subject
{
public string Name { get; set; }
public abstract void RegisterSubscriber(Observer observer);
public abstract void RemoveSubscriber(Observer observer);
public abstract void NotifyObservers();
}
public abstract class Observer
{
public string Name { get; set; }
public abstract void Update(string content, string subjectName);
}
public class Youtuber : Subject
{
private readonly List<Observer> _observers;
private string _content = String.Empty;
public Youtuber(string name)
{
_observers = new List<Observer>();
Name = name;
}
public void UploadNewVideo(string content)
{
_content = content;
NotifyObservers();
}
public override void RegisterSubscriber(Observer observer)
{
_observers.Add(observer);
Console.WriteLine($"{observer.Name}訂閱{this.Name}成功!");
}
public override void RemoveSubscriber(Observer observer)
{
_observers.Remove(_observers.Find(x => x == observer));
Console.WriteLine($"{observer.Name}取消訂閱{this.Name}!");
}
public override void NotifyObservers()
{
_observers.ForEach(x => x.Update(_content, this.Name));
}
}
public class Subscriber : Observer
{
public Subscriber(string name)
{
// Name為抽象類別共通的屬性值
Name = name;
}
// Youtuber會使用NotifyObservers()方法,觸發這裡改寫的Update()通知
public override void Update(string content, string youtuberName)
{
Console.WriteLine($"{Name}收到{youtuberName}最新影片的通知,內容為:{content}");
}
}
}
Observer模式 (觀察者模式)主要的重點是在處理一對多的相依關係,從例子來看,Youtuber
可以去註冊很多的Subscriber
,並且藉由NotifyObservers()
方法就能對所有的Subscriber
做到通知的功能。